Multithreading

C# supports multithreaded programming. A multithreaded program contains two or more parts that can run concurrently. Each part of such a program is called a thread, and each thread defines a separate path of execution. Thus, multithreading is a specialized form of multitasking.

Multithreaded programming relies on a combination of features defined by the C# language and by classes in the .NET Framework. Because support of multithreading is built into C#, many of the problems associated with multithreading in other languages are minimized or eliminated.
There are two distinct types of multitasking: process-based and thread-based. It is important to understand the difference between the two. A process is, in essence, a program that is executing. Thus, process-based multitasking is the feature that allows your computer to run two or more programs concurrently. For example, it is process-based multitasking that allows you to run a word processor at the same time you are using a spreadsheet or browsing the Internet. In process-based multitasking, a program is the smallest unit of code that can be dispatched by the scheduler.
A thread is a dispatch able unit of executable code. In a thread-based multitasking environment, all processes have at least one thread, but they can have more. This means that a single program can perform two or more tasks at once. For instance, a text editor can be formatting text at the same time that it is printing, as long as these two actions are being performed by two separate threads.
Process-based multitasking handles the concurrent execution of programs. Thread-based multitasking deals with the concurrent execution of pieces of the same program.
The .NET Framework defines two types of threads: foreground and background. By default, when you create a thread, it is a foreground thread, but you can change it to a background thread. The only difference between foreground and background threads is that a background thread will be automatically terminated when all foreground threads in its process have stopped.
The classes that support multithreaded programming are defined in the System.Threading namespace. Thus, you will usually include this statement at the start of any multithreaded program:

using System.Threading;

 

C#’s multithreading system is built upon the Thread class, which encapsulates a thread of execution. The Thread class is sealed, which means that it cannot be inherited.

 

 

The classes available in the System. Threading namespace


Class

Description

AutoResetEvent

This event notifies one or more waiting threads that an event has occurred.

Interlocked

This class protects against errors by providing atomic operations for variables that are shared by multiple threads.

ManualResetEvent

This event occurs when notifying one or more waiting threads that an event has occurred.

Monitor

This class provides a mechanism that synchronizes access to objects.

Mutex

A synchronization primitive that grants exclusive access to a shared resource to only one thread. It can also be used for inter-process synchronization.

ReaderWriterLock

This class defines a lock that allows single-writer and multiple-reader semantics.

RegisteredWaitHandle

This class represents a handle that has been registered when calling the RegisterWaitForSingleObject() method.

SynchronizationLockException

This exception is thrown when a synchronized method is invoked from an unsynchronized block of code.

Thread

This class creates and controls a thread, sets its priority, and gets its status.

ThreadAbortException

This exception is thrown when a call is made to the Abort() method.

ThreadExceptionEventArgs

This class provides data for the ThreadException event.

ThreadInterruptedException

This exception is thrown when a thread is interrupted while it is in a waiting state.

ThreadPool

This class provides a pool of threads that can be used to post work items, process asynchronous I/O, wait on behalf of other threads, and process timers.

ThreadStateException

This is the exception that is thrown when a thread is in an invalid state for the method call.

Timeout

This class simply contains a constant integer used when we want to specify an infinite amount of time.

Timer

This class provides a mechanism for executing methods at specified intervals.

WaitHandle

This class encapsulates operating system-specific objects that wait for exclusive access to shared resources.

 

Thread Class Methods

Public Method Name

Description

Abort()

This overloaded method raises a ThreadAbortException in the thread on which it is invoked, to begin the process of terminating the thread. Calling this method usually terminates the thread.

AllocateDataSlot()

This static method allocates an unnamed data slot on all the threads.

AllocateNamedDataSlot()

This static method allocates a named data slot on all threads.

FreeNamedDataSlot()

This static method frees a previously allocated named data slot.

GetData()

This static method retrieves the value from the specified slot on the current thread, within the current thread's current domain.

GetDomain()

This static method returns the current domain in which the current thread is running.

GetDomainID()

This static method returns a unique application domain identifier.

GetHashCode()

This method serves as a hash function for a particular type, suitable for use in hashing algorithms and data structures like a hash table.

GetNamedDataSlot()

This static method looks up a named data slot.

Interrupt()

This method interrupts a thread that is in the WaitSleepJoin thread state.

Join()

This overloaded method blocks the calling thread until a thread terminates.

ResetAbort()

This static method cancels an Abort() requested for the current thread.

Resume()

This method resumes a thread that has been suspended.

SetData()

This static method sets the data in the specified slot on the currently running thread, for that thread's current domain.

Sleep()

This static and overloaded method blocks the current thread for the specified number of milliseconds.

SpinWait()

This static method causes a thread to wait the number of times defined by the iterations parameter.

Start()

This method causes the operating system to change the state of the current instance to ThreadState.Running.

Suspend()

This method will either suspend the thread, or if the thread is already suspended, has no effect.

 

Public Properties of Thread


Public Property Name

Description

ApartmentState

Sets or gets the apartment state of this thread.

CurrentContext

This static property gets the current context in which the thread is executing.

CurrentCulture

Sets or gets the culture for the current thread.

CurrentPrincipal

This static property sets or gets the thread's current principal. It is used for role-based security.

CurrentThread

This static property gets the currently running thread.

CurrentUICulture

Used at run time, this property sets or gets the current culture used by the Resource Manager to look up culture-specific resources.

IsAlive

Gets a value that indicates the execution status of the current thread.

IsBackground

Sets or gets a value that indicates whether a thread is a background thread or not.

IsThreadPoolThread

Gets a value indicating whether a thread is part of a thread pool.

Name

Sets or gets the name of the thread.

Priority

Sets or gets a value that indicates the scheduling priority of a thread.

ThreadState

Gets a value that contains the states of the current thread.

Thread States

The state of a thread can be obtained from the ThreadState property provided by Thread

 

ThreadState.Aborted

ThreadState.AbortRequested

ThreadState.Background

ThreadState.Running

ThreadState.Stopped

ThreadState.StopRequested

ThreadState.Suspended

ThreadState.SuspendRequested

ThreadState.Unstarted

ThreadState.WaitSleepJoin

 

The simplest way to create a thread is to create a new instance of the Thread class. The Thread constructor takes a single argument: a delegate type. The CLR provides the ThreadStart delegate class specifically for this purpose, which points to a method you designate. This allows you to construct a thread and to say to that thread "when you start, run this method."

Program on multithreading with another modal
using System;
using System.Threading;

class abc
{
string tName;
Thread t;
public abc(string name)
{
tName = name;
t=new Thread(this.run);
t.Start();
}

    public void run()
{
Console.WriteLine(tName + " starting.");

        for(int c=0;c<10;c++)

{
Thread.Sleep(500);
Console.WriteLine("In " + tName +", count is " + c);
}

        Console.WriteLine(tName + " terminating.");
}
}

class MultiThread
{
public static void Main()
{
Console.WriteLine("Main thread starting.");

                abc mt = new abc("Child #1");
for(int c=0;c<10;c++)      
{
Console.Write(".");
Thread.Sleep(100);
}

        Console.WriteLine("Main thread ending.");
}
}

Program on Multiple Threads

using System;
using System.Threading;

class abc
{
string tName;
Thread t;
public abc(string name)
{
tName = name;
t=new Thread(this.run);
t.Start();
}

    public void run()
{
Console.WriteLine(tName + " starting.");

        for(int c=0;c<10;c++)

{
Thread.Sleep(500);
Console.WriteLine("In " + tName +", count is " + c);
}

        Console.WriteLine(tName + " terminating.");
}
}

class vision
{
public static void Main()
{
Console.WriteLine("Main thread starting.");

                abc t1 = new abc("Child #1");
abc t2= new abc("Child #2");
abc t3= new abc("Child #3");

        for(int c=0;c<10;c++)      
{
Console.Write(".");
Thread.Sleep(1000);
}

        Console.WriteLine("Main thread ending.");
}
}

Program on IsAlive and Join

using System;
using System.Threading;

class abc
{
string tName;
public Thread t;
public abc(string name)
{
tName = name;
t=new Thread(this.run);
t.Start();
}

    public void run()
{
Console.WriteLine(tName + " starting.");

        for(int c=0;c<10;c++)

{
Thread.Sleep(500);
Console.WriteLine("In " + tName +", count is " + c);
}

        Console.WriteLine(tName + " terminating.");
}
}

class vision
{
public static void Main()
{
Console.WriteLine("Main thread starting.");

                abc t1 = new abc("Child #1");
abc t2= new abc("Child #2");
abc t3= new abc("Child #3");
Console.WriteLine(t1.t.IsAlive());
Console.WriteLine(t1.t.IsAlive());
Console.WriteLine(t1.t.IsAlive());
t1.t.Join();
t2.t.Join();
t3.t.Join();
Console.WriteLine(t1.t.IsAlive());
Console.WriteLine(t1.t.IsAlive());
Console.WriteLine(t1.t.IsAlive());

 

        Console.WriteLine("Main thread ending.");
}
}

Arguments to Thread

From the C#2.0 onwards we can pass an argument to a thread. To do so, you must use new forms of Start( ), the Thread constructor, and the entry point method. To start a thread we need to use ParameterizedThreadStart rather than ThreadStart delegate.

Program on parameterized thread
using System;
using System.Threading;

class abc
{
string tName;
public Thread t;

public abc(string name,int n)
{
tName = name;
t = new Thread(new ParameterizedThreadStart ( this.run));
t.Start(n) ;
}

    public void run(object n)
{
Console.WriteLine(tName + " starting.");

        for (int c = 0; c < (int)n; c++)
{
Thread.Sleep(500);
Console.WriteLine("In " + tName + ", count is " + c);
}

        Console.WriteLine(tName + " terminating.");
}
}

class vision
{
public static void Main()
{
Console.WriteLine("Main thread starting.");

        abc t1 = new abc("Child #1",3);
abc t2 = new abc("Child #2",5);
abc t3 = new abc("Child #3",4);

        t1.t.Join();
t2.t.Join();
t3.t.Join();
Console.WriteLine("Main thread ending.");
string s = Console.ReadLine();
}
}

 

Thread Priorities
You can change a thread’s priority through the Priority property, which is a member of Thread.
ThreadPriority is an enumeration that defines the following five priority settings:

ThreadPriority.Highest
ThreadPriority.AboveNormal
ThreadPriority.Normal
ThreadPriority.BelowNormal
ThreadPriority.Lowest

The default priority setting for a thread is ThreadPriority.Normal.
Program on Thread Priority’s

using System;
using System.Threading;

class abc
{
public long  c;
public Thread t;
static bool stop = false;
static string tName;

   
public abc(string name)
{
c = 0;
t = new Thread(this.run);
t.Name = name;
tName = name;
}

void run()
{
Console.WriteLine(t.Name + " starting.");
do
{
c++;
} while (stop == false );

Console.WriteLine(t.Name + " terminating.");
}
public void term()
{
stop = true;
}
}

class vision
{
public static void Main()
{
abc mt1 = new abc("High Priority");
abc mt2 = new abc("Low Priority");

       
mt1.t.Priority = ThreadPriority.AboveNormal;
mt2.t.Priority = ThreadPriority.BelowNormal;

       
mt1.t.Start();
mt2.t.Start();
Thread.Sleep(100);

mt1.term();
mt2.term();
mt1.t.Join();
mt2.t.Join();

        Console.WriteLine();
Console.WriteLine(mt1.t.Name + " thread counted to " +
mt1.c);
Console.WriteLine(mt2.t.Name + " thread counted to " +
mt2.c);
}
}